home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / Kasumi / source / resample.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-04-16  |  39.4 KB  |  1,361 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Graphics support library
  3. //    Copyright (C) 1998-2004 Avery Lee
  4. //
  5. //    This program is free software; you can redistribute it and/or modify
  6. //    it under the terms of the GNU General Public License as published by
  7. //    the Free Software Foundation; either version 2 of the License, or
  8. //    (at your option) any later version.
  9. //
  10. //    This program is distributed in the hope that it will be useful,
  11. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //    GNU General Public License for more details.
  14. //
  15. //    You should have received a copy of the GNU General Public License
  16. //    along with this program; if not, write to the Free Software
  17. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include <float.h>
  20. #include <math.h>
  21. #include <vd2/system/vdstl.h>
  22. #include <vd2/system/memory.h>
  23. #include <vd2/system/math.h>
  24. #include <vd2/system/cpuaccel.h>
  25. #include <vd2/Kasumi/pixmap.h>
  26. #include <vd2/Kasumi/pixmaputils.h>
  27. #include <vd2/Kasumi/resample.h>
  28.  
  29. ///////////////////////////////////////////////////////////////////////////
  30. //
  31. // utility functions
  32. //
  33. ///////////////////////////////////////////////////////////////////////////
  34.  
  35. namespace {
  36.     sint32 scale32x32_fp16(sint32 x, sint32 y) {
  37.         return (sint32)(((sint64)x * y + 0x8000) >> 16);
  38.     }
  39. }
  40.  
  41. ///////////////////////////////////////////////////////////////////////////
  42. //
  43. // sampling calculations
  44. //
  45. ///////////////////////////////////////////////////////////////////////////
  46.  
  47. namespace {
  48.     struct VDResamplerAxis {
  49.         sint32        dx;
  50.         sint32        u;
  51.         sint32        dudx;
  52.         uint32        dx_precopy;
  53.         uint32        dx_preclip;
  54.         uint32        dx_active;
  55.         uint32        dx_postclip;
  56.         uint32        dx_postcopy;
  57.         uint32        dx_dualclip;
  58.  
  59.         void Init(sint32 dudx);
  60.         void Compute(sint32 x1, sint32 x2, sint32 fx1_unclipped, sint32 u0, sint32 w, sint32 kernel_width);
  61.     };
  62.  
  63.     void VDResamplerAxis::Init(sint32 dudx) {
  64.         this->dudx = dudx;
  65.     }
  66.  
  67.     void VDResamplerAxis::Compute(sint32 x1, sint32 x2, sint32 fx1_unclipped, sint32 u0, sint32 w, sint32 kernel_width) {
  68.         u = u0 + scale32x32_fp16(dudx, ((x1<<16)+0x8000) - fx1_unclipped);
  69.  
  70.         dx = x2-x1;
  71.  
  72.         sint32 du_kern    = (kernel_width-1) << 16;
  73.         sint32 u2        = u + dudx*(dx-1);
  74.         sint32 u_limit    = w << 16;
  75.  
  76.         dx_precopy    = 0;
  77.         dx_preclip    = 0;
  78.         dx_active    = 0;
  79.         dx_postclip    = 0;
  80.         dx_postcopy = 0;
  81.         dx_dualclip    = 0;
  82.  
  83.         sint32 dx_temp = dx;
  84.         sint32 u_start = u;
  85.  
  86.         // (desired - u0 + (dudx-1)) / dudx : first pixel >= desired
  87.  
  88.         sint32 dudx_m1_mu0    = dudx - 1 - u;
  89.         sint32 first_preclip    = (dudx_m1_mu0 + 0x10000 - du_kern) / dudx;
  90.         sint32 first_active        = (dudx_m1_mu0                    ) / dudx;
  91.         sint32 first_postclip    = (dudx_m1_mu0 + u_limit - du_kern) / dudx;
  92.         sint32 first_postcopy    = (dudx_m1_mu0 + u_limit - 0x10000) / dudx;
  93.  
  94.         // clamp
  95.         if (first_preclip < 0)
  96.             first_preclip = 0;
  97.         if (first_active < first_preclip)
  98.             first_active = first_preclip;
  99.         if (first_postclip < first_active)
  100.             first_postclip = first_active;
  101.         if (first_postcopy < first_postclip)
  102.             first_postcopy = first_postclip;
  103.         if (first_preclip > dx)
  104.             first_preclip = dx;
  105.         if (first_active > dx)
  106.             first_active = dx;
  107.         if (first_postclip > dx)
  108.             first_postclip = dx;
  109.         if (first_postcopy > dx)
  110.             first_postcopy = dx;
  111.  
  112.         // determine widths
  113.  
  114.         dx_precopy    = first_preclip;
  115.         dx_preclip    = first_active - first_preclip;
  116.         dx_active    = first_postclip - first_active;
  117.         dx_postclip    = first_postcopy - first_postclip;
  118.         dx_postcopy    = dx - first_postcopy;
  119.  
  120.         // sanity checks
  121.         sint32 pos0 = dx_precopy;
  122.         sint32 pos1 = pos0 + dx_preclip;
  123.         sint32 pos2 = pos1 + dx_active;
  124.         sint32 pos3 = pos2 + dx_postclip;
  125.  
  126.         VDASSERT(!((dx_precopy|dx_preclip|dx_active|dx_postcopy|dx_postclip) & 0x80000000));
  127.         VDASSERT(dx_precopy + dx_preclip + dx_active + dx_postcopy + dx_postclip == dx);
  128.  
  129.         VDASSERT(!pos0            || u_start + dudx*(pos0 - 1) <  0x10000 - du_kern);    // precopy -> preclip
  130.         VDASSERT( pos0 >= pos1    || u_start + dudx*(pos0    ) >= 0x10000 - du_kern);
  131.         VDASSERT( pos1 <= pos0    || u_start + dudx*(pos1 - 1) <  0);                    // preclip -> active
  132.         VDASSERT( pos1 >= pos2    || u_start + dudx*(pos1    ) >= 0 || !dx_active);
  133.         VDASSERT( pos2 <= pos1    || u_start + dudx*(pos2 - 1) <  u_limit - du_kern || !dx_active);    // active -> postclip
  134.         VDASSERT( pos2 >= pos3    || u_start + dudx*(pos2    ) >= u_limit - du_kern);
  135.         VDASSERT( pos3 <= pos2    || u_start + dudx*(pos3 - 1) <  u_limit - 0x10000);    // postclip -> postcopy
  136.         VDASSERT( pos3 >= dx    || u_start + dudx*(pos3    ) >= u_limit - 0x10000);
  137.  
  138.         u += dx_precopy * dudx;
  139.  
  140.         // test for overlapping clipping regions
  141.         if (!dx_active) {
  142.             dx_dualclip = dx_preclip + dx_postclip;
  143.             dx_preclip = dx_postclip = 0;
  144.         }
  145.     }
  146.  
  147.     struct VDResamplerInfo {
  148.         void        *mpDst;
  149.         ptrdiff_t    mDstPitch;
  150.         const void    *mpSrc;
  151.         ptrdiff_t    mSrcPitch;
  152.         vdpixsize    mSrcW;
  153.         vdpixsize    mSrcH;
  154.  
  155.         VDResamplerAxis mXAxis;
  156.         VDResamplerAxis mYAxis;
  157.     };
  158. }
  159.  
  160. ///////////////////////////////////////////////////////////////////////////
  161. //
  162. // allocation
  163. //
  164. ///////////////////////////////////////////////////////////////////////////
  165.  
  166. namespace {
  167.     class VDSteppedAllocator {
  168.     public:
  169.         typedef    size_t        size_type;
  170.         typedef    ptrdiff_t    difference_type;
  171.  
  172.         VDSteppedAllocator(size_t initialSize = 1024);
  173.         ~VDSteppedAllocator();
  174.  
  175.         void clear();
  176.         void *allocate(size_type n);
  177.  
  178.     protected:
  179.         struct Block {
  180.             Block *next;
  181.         };
  182.  
  183.         Block *mpHead;
  184.         char *mpAllocNext;
  185.         size_t    mAllocLeft;
  186.         size_t    mAllocNext;
  187.         size_t    mAllocInit;
  188.     };
  189.     
  190.     VDSteppedAllocator::VDSteppedAllocator(size_t initialSize)
  191.         : mpHead(NULL)
  192.         , mpAllocNext(NULL)
  193.         , mAllocLeft(0)
  194.         , mAllocNext(initialSize)
  195.         , mAllocInit(initialSize)
  196.     {
  197.     }
  198.  
  199.     VDSteppedAllocator::~VDSteppedAllocator() {
  200.         clear();
  201.     }
  202.  
  203.     void VDSteppedAllocator::clear() {
  204.         while(Block *p = mpHead) {
  205.             mpHead = mpHead->next;
  206.             free(p);
  207.         }
  208.         mAllocLeft = 0;
  209.         mAllocNext = mAllocInit;
  210.     }
  211.  
  212.     void *VDSteppedAllocator::allocate(size_type n) {
  213.         n = (n+15) & ~15;
  214.         if (mAllocLeft < n) {
  215.             mAllocLeft = mAllocNext;
  216.             mAllocNext += (mAllocNext >> 1);
  217.             if (mAllocLeft < n)
  218.                 mAllocLeft = n;
  219.  
  220.             Block *t = (Block *)malloc(sizeof(Block) + mAllocLeft);
  221.  
  222.             if (mpHead)
  223.                 mpHead->next = t;
  224.  
  225.             mpHead = t;
  226.             mpHead->next = NULL;
  227.  
  228.             mpAllocNext = (char *)(mpHead + 1);
  229.         }
  230.  
  231.         void *p = mpAllocNext;
  232.         mpAllocNext += n;
  233.         mAllocLeft -= n;
  234.         return p;
  235.     }
  236. }
  237.  
  238. ///////////////////////////////////////////////////////////////////////////
  239. //
  240. // filter kernels
  241. //
  242. ///////////////////////////////////////////////////////////////////////////
  243.  
  244. namespace {
  245.     class IVDResamplerFilter {
  246.     public:
  247.         virtual int GetFilterWidth() const = 0;
  248.         virtual void GenerateFilterBank(float *dst) const = 0;
  249.     };
  250.  
  251.     class VDResamplerLinearFilter : public IVDResamplerFilter {
  252.     public:
  253.         VDResamplerLinearFilter(double twofc)
  254.             : mScale(twofc)
  255.             , mTaps((int)ceil(1.0 / twofc) * 2)
  256.         {
  257.         }
  258.  
  259.         int GetFilterWidth() const { return mTaps; }
  260.  
  261.         void GenerateFilterBank(float *dst) const {
  262.             const double basepos = -(double)((mTaps>>1)-1) * mScale;
  263.             for(int offset=0; offset<256; ++offset) {
  264.                 double pos = basepos - offset*((1.0/256.0) * mScale);
  265.  
  266.                 for(unsigned i=0; i<mTaps; ++i) {
  267.                     double t = 1.0 - fabs(pos);
  268.  
  269.                     *dst++ = (float)(t+fabs(t));
  270.                     pos += mScale;
  271.                 }
  272.             }
  273.         }
  274.  
  275.     protected:
  276.         double        mScale;
  277.         unsigned    mTaps;
  278.     };
  279.  
  280.     class VDResamplerCubicFilter : public IVDResamplerFilter {
  281.     public:
  282.         VDResamplerCubicFilter(double twofc, double A)
  283.             : mScale(twofc)
  284.             , mA(A)
  285.             , mTaps((int)ceil(2.0 / twofc)*2)
  286.         {
  287.         }
  288.  
  289.         int GetFilterWidth() const { return mTaps; }
  290.  
  291.         void GenerateFilterBank(float *dst) const {
  292.             const double a0 = ( 1.0  );
  293.             const double a2 = (-3.0-mA);
  294.             const double a3 = ( 2.0+mA);
  295.             const double b0 = (-4.0*mA);
  296.             const double b1 = ( 8.0*mA);
  297.             const double b2 = (-5.0*mA);
  298.             const double b3 = (     mA);
  299.             const double basepos = -(double)((mTaps>>1)-1) * mScale;
  300.  
  301.             for(int offset=0; offset<256; ++offset) {
  302.                 double pos = basepos - offset*((1.0f/256.0f) * mScale);
  303.  
  304.                 for(unsigned i=0; i<mTaps; ++i) {
  305.                     double t = fabs(pos);
  306.                     double v = 0;
  307.  
  308.                     if (t < 1.0)
  309.                         v = a0 + (t*t)*(a2 + t*a3);
  310.                     else if (t < 2.0)
  311.                         v = b0 + t*(b1 + t*(b2 + t*b3));
  312.  
  313.                     *dst++ = (float)v;
  314.                     pos += mScale;
  315.                 }
  316.             }
  317.         }
  318.  
  319.     protected:
  320.         double        mScale;
  321.         double        mA;
  322.         unsigned    mTaps;
  323.     };
  324.  
  325.     static inline double sinc(double x) {
  326.         return fabs(x) < 1e-9 ? 1.0 : sin(x) / x;
  327.     }
  328.  
  329.     class VDResamplerLanczos3Filter : public IVDResamplerFilter {
  330.     public:
  331.         VDResamplerLanczos3Filter(double twofc)
  332.             : mScale(twofc)
  333.             , mTaps((int)ceil(3.0 / twofc)*2)
  334.         {
  335.         }
  336.  
  337.         int GetFilterWidth() const { return mTaps; }
  338.  
  339.         void GenerateFilterBank(float *dst) const {
  340.             static const double pi  = 3.1415926535897932384626433832795;    // pi
  341.             static const double pi3 = 1.0471975511965977461542144610932;    // pi/3
  342.             const double basepos = -(double)((mTaps>>1)-1) * mScale;
  343.  
  344.             for(int offset=0; offset<256; ++offset) {
  345.                 double t = basepos - offset*((1.0/256.0) * mScale);
  346.  
  347.                 for(unsigned i=0; i<mTaps; ++i) {
  348.                     double v = 0;
  349.  
  350.                     if (t < 3.0)
  351.                         v = sinc(pi*t) * sinc(pi3*t);
  352.  
  353.                     *dst++ = (float)v;
  354.                     t += mScale;
  355.                 }
  356.             }
  357.         }
  358.  
  359.     protected:
  360.         double        mScale;
  361.         unsigned    mTaps;
  362.     };
  363. }
  364.  
  365. ///////////////////////////////////////////////////////////////////////////
  366. //
  367. // resampler stages (common)
  368. //
  369. ///////////////////////////////////////////////////////////////////////////
  370.  
  371. class IVDResamplerStage {
  372. public:
  373.     virtual ~IVDResamplerStage() {}
  374.  
  375.     void *operator new(size_t n, VDSteppedAllocator& a) {
  376.         return a.allocate(n);
  377.     }
  378.  
  379.     void operator delete(void *p, VDSteppedAllocator& a) {
  380.     }
  381.  
  382.     virtual void Process(const VDResamplerInfo& info) {}
  383.  
  384.     virtual sint32 GetHorizWindowSize() const { return 1; }
  385.     virtual sint32 GetVertWindowSize() const { return 1; }
  386.  
  387. private:
  388.     // these should NEVER be called
  389.     void operator delete(void *p) {}
  390. };
  391.  
  392. class IVDResamplerSeparableRowStage : public IVDResamplerStage {
  393. public:
  394.     virtual void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) = 0;
  395.     virtual int GetWindowSize() const = 0;
  396. };
  397.  
  398. class IVDResamplerSeparableColStage : public IVDResamplerStage {
  399. public:
  400.     virtual int GetWindowSize() const = 0;
  401.     virtual void Process(void *dst, const void *const *src, uint32 w, sint32 phase) = 0;
  402. };
  403.  
  404. ///////////////////////////////////////////////////////////////////////////
  405. //
  406. // resampler stages (portable)
  407. //
  408. ///////////////////////////////////////////////////////////////////////////
  409.  
  410. namespace {
  411.     void GenerateTable(sint32 *dst, const IVDResamplerFilter& filter) {
  412.         const unsigned width = filter.GetFilterWidth();
  413.         vdblock<float> filters(width * 256);
  414.         float *src = filters.data();
  415.  
  416.         filter.GenerateFilterBank(src);
  417.  
  418.         for(unsigned phase=0; phase < 256; ++phase) {
  419.             float sum = 0;
  420.  
  421.             for(unsigned i=0; i<width; ++i)
  422.                 sum += src[i];
  423.  
  424.             float scalefac = 16384.0f / sum;
  425.  
  426.             for(unsigned j=0; j<width; j += 2) {
  427.                 int v0 = VDRoundToIntFast(src[j+0] * scalefac);
  428.                 int v1 = VDRoundToIntFast(src[j+1] * scalefac);
  429.  
  430.                 dst[j+0] = v0;
  431.                 dst[j+1] = v1;
  432.             }
  433.  
  434.             src += width;
  435.             dst += width;
  436.         }
  437.     }
  438.  
  439.     void SwizzleTable(sint32 *dst, unsigned pairs) {
  440.         do {
  441.             sint32 v0 = dst[0];
  442.             sint32 v1 = dst[1];
  443.  
  444.             dst[0] = dst[1] = (v0 & 0xffff) + (v1<<16);
  445.             dst += 2;
  446.         } while(--pairs);
  447.     }
  448. }
  449.  
  450. class VDResamplerSeparablePointRowStage : public IVDResamplerSeparableRowStage {
  451. public:
  452.     int GetWindowSize() const {return 1;}
  453.     void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) {
  454.         uint32 *dst = (uint32 *)dst0;
  455.         const uint32 *src = (const uint32 *)src0;
  456.  
  457.         do {
  458.             *dst++ = src[u>>16];
  459.             u += dudx;
  460.         } while(--w);
  461.     }
  462. };
  463.  
  464. class VDResamplerSeparableLinearRowStage : public IVDResamplerSeparableRowStage {
  465. public:
  466.     int GetWindowSize() const {return 2;}
  467.     void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) {
  468.         uint32 *dst = (uint32 *)dst0;
  469.         const uint32 *src = (const uint32 *)src0;
  470.  
  471.         do {
  472.             const sint32 iu = u>>16;
  473.             const uint32 p0 = src[iu];
  474.             const uint32 p1 = src[iu+1];
  475.             const uint32 f = (u >> 8) & 0xff;
  476.  
  477.             const uint32 p0_rb = p0 & 0xff00ff;
  478.             const uint32 p1_rb = p1 & 0xff00ff;
  479.             const uint32 p0_g = p0 & 0xff00;
  480.             const uint32 p1_g = p1 & 0xff00;
  481.  
  482.             *dst++    = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff)
  483.                     + ((p0_g  + (((p1_g  - p0_g )*f + 0x008000)>>8)) & 0x00ff00);
  484.             u += dudx;
  485.         } while(--w);
  486.     }
  487. };
  488.  
  489. class VDResamplerSeparableLinearColStage : public IVDResamplerSeparableColStage {
  490. public:
  491.     int GetWindowSize() const {return 2;}
  492.     void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) {
  493.         uint32 *dst = (uint32 *)dst0;
  494.         const uint32 *src0 = (const uint32 *)srcarray[0];
  495.         const uint32 *src1 = (const uint32 *)srcarray[1];
  496.         const uint32 f = (phase >> 8) & 0xff;
  497.  
  498.         do {
  499.             const uint32 p0 = *src0++;
  500.             const uint32 p1 = *src1++;
  501.  
  502.             const uint32 p0_rb = p0 & 0xff00ff;
  503.             const uint32 p1_rb = p1 & 0xff00ff;
  504.             const uint32 p0_g = p0 & 0xff00;
  505.             const uint32 p1_g = p1 & 0xff00;
  506.  
  507.             *dst++    = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff)
  508.                     + ((p0_g  + (((p1_g  - p0_g )*f + 0x008000)>>8)) & 0x00ff00);
  509.         } while(--w);
  510.     }
  511. };
  512.  
  513. class VDResamplerSeparableTableRowStage : public IVDResamplerSeparableRowStage {
  514. public:
  515.     VDResamplerSeparableTableRowStage(const IVDResamplerFilter& filter) {
  516.         mFilterBank.resize(filter.GetFilterWidth() * 256);
  517.         GenerateTable(mFilterBank.data(), filter);
  518.     }
  519.  
  520.     int GetWindowSize() const {return mFilterBank.size() >> 8;}
  521.  
  522.     void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) {
  523.         uint32 *dst = (uint32 *)dst0;
  524.         const uint32 *src = (const uint32 *)src0;
  525.         const unsigned ksize = mFilterBank.size() >> 8;
  526.         const sint32 *filterBase = mFilterBank.data();
  527.  
  528.         do {
  529.             const uint32 *src2 = src + (u>>16);
  530.             const sint32 *filter = filterBase + ksize*((u>>8)&0xff);
  531.             u += dudx;
  532.  
  533.             int r = 0x8000, g = 0x8000, b = 0x8000;
  534.             for(unsigned i = ksize; i; --i) {
  535.                 uint32 p = *src2++;
  536.                 sint32 coeff = *filter++;
  537.  
  538.                 r += ((p>>16)&0xff)*coeff;
  539.                 g += ((p>> 8)&0xff)*coeff;
  540.                 b += ((p    )&0xff)*coeff;
  541.             }
  542.  
  543.             r <<= 2;
  544.             g >>= 6;
  545.             b >>= 14;
  546.  
  547.             if ((uint32)r >= 0x01000000)
  548.                 r = ~r >> 31;
  549.             if ((uint32)g >= 0x00010000)
  550.                 g = ~g >> 31;
  551.             if ((uint32)b >= 0x00000100)
  552.                 b = ~b >> 31;
  553.  
  554.             *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff);
  555.         } while(--w);
  556.     }
  557.  
  558. protected:
  559.     vdblock<sint32, vdaligned_alloc<sint32> >    mFilterBank;
  560. };
  561.  
  562. class VDResamplerSeparableTableColStage : public IVDResamplerSeparableColStage {
  563. public:
  564.     VDResamplerSeparableTableColStage(const IVDResamplerFilter& filter) {
  565.         mFilterBank.resize(filter.GetFilterWidth() * 256);
  566.         GenerateTable(mFilterBank.data(), filter);
  567.     }
  568.  
  569.     int GetWindowSize() const {return mFilterBank.size() >> 8;}
  570.  
  571.     void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) {
  572.         uint32 *dst = (uint32 *)dst0;
  573.         const uint32 *const *src = (const uint32 *const *)src0;
  574.         const unsigned ksize = mFilterBank.size() >> 8;
  575.         const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize];
  576.  
  577.         for(uint32 i=0; i<w; ++i) {
  578.             int r = 0x8000, g = 0x8000, b = 0x8000;
  579.             const sint32 *filter2 = filter;
  580.             const uint32 *const *src2 = src;
  581.  
  582.             for(unsigned j = ksize; j; --j) {
  583.                 uint32 p = (*src2++)[i];
  584.                 sint32 coeff = *filter2++;
  585.  
  586.                 r += ((p>>16)&0xff)*coeff;
  587.                 g += ((p>> 8)&0xff)*coeff;
  588.                 b += ((p    )&0xff)*coeff;
  589.             }
  590.  
  591.             r <<= 2;
  592.             g >>= 6;
  593.             b >>= 14;
  594.  
  595.             if ((uint32)r >= 0x01000000)
  596.                 r = ~r >> 31;
  597.             if ((uint32)g >= 0x00010000)
  598.                 g = ~g >> 31;
  599.             if ((uint32)b >= 0x00000100)
  600.                 b = ~b >> 31;
  601.  
  602.             *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff);
  603.         } while(--w);
  604.     }
  605.  
  606. protected:
  607.     vdblock<sint32, vdaligned_alloc<sint32> >    mFilterBank;
  608. };
  609.  
  610. class VDResamplerSeparableStage : public IVDResamplerStage {
  611. public:
  612.     VDResamplerSeparableStage(IVDResamplerSeparableRowStage *pRow, IVDResamplerSeparableColStage *pCol);
  613.     ~VDResamplerSeparableStage() {
  614.         if (mpRowStage)
  615.             mpRowStage->~IVDResamplerSeparableRowStage();
  616.         if (mpColStage)
  617.             mpColStage->~IVDResamplerSeparableColStage();
  618.     }
  619.  
  620.     void Process(const VDResamplerInfo&);
  621.  
  622.     sint32 GetHorizWindowSize() const { return mpRowStage ? mpRowStage->GetWindowSize() : 1; }
  623.     sint32 GetVertWindowSize() const { return mpColStage ? mpColStage->GetWindowSize() : 1; }
  624.  
  625. protected:
  626.     void ProcessPoint();
  627.     void ProcessComplex();
  628.     void ProcessRow(void *dst, const void *src);
  629.  
  630.     IVDResamplerSeparableRowStage *const mpRowStage;
  631.     IVDResamplerSeparableColStage *const mpColStage;
  632.  
  633.     uint32                mWinSize;
  634.     uint32                mRowFiltW;
  635.  
  636.     VDResamplerInfo        mInfo;
  637.  
  638.     vdblock<void *>    mWindow;
  639.     void                **mpAllocWindow;
  640.     vdblock<uint32, vdaligned_alloc<uint32> >        mTempSpace;
  641. };
  642.  
  643. VDResamplerSeparableStage::VDResamplerSeparableStage(IVDResamplerSeparableRowStage *pRow, IVDResamplerSeparableColStage *pCol)
  644.     : mpRowStage(pRow)
  645.     , mpColStage(pCol)
  646. {
  647.     mWinSize = mpColStage ? mpColStage->GetWindowSize() : 1;
  648.     mRowFiltW = mpRowStage->GetWindowSize();
  649.     mWindow.resize(3*mWinSize);
  650. }
  651.  
  652. void VDResamplerSeparableStage::Process(const VDResamplerInfo& info) {
  653.     mInfo = info;
  654.  
  655.     if (mpColStage || (mpRowStage->GetWindowSize()>1 && mInfo.mYAxis.dudx < 0x10000))
  656.         ProcessComplex();
  657.     else
  658.         ProcessPoint();
  659. }
  660.  
  661. void VDResamplerSeparableStage::ProcessPoint() {
  662.     mTempSpace.resize(mRowFiltW*3);
  663.  
  664.     const uint32 winsize = mWinSize;
  665.     const uint32 dx = mInfo.mXAxis.dx;
  666.  
  667.     const uint32 *src = (const uint32 *)mInfo.mpSrc;
  668.     const ptrdiff_t srcpitch = mInfo.mSrcPitch;
  669.     const sint32 srch = mInfo.mSrcH;
  670.     void *dst = mInfo.mpDst;
  671.     const ptrdiff_t dstpitch = mInfo.mDstPitch;
  672.  
  673.  
  674.     if (uint32 count = mInfo.mYAxis.dx_precopy) {
  675.         do {
  676.             ProcessRow(dst, src);
  677.             vdptrstep(dst, dstpitch);
  678.         } while(--count);
  679.     }
  680.  
  681.     if (uint32 count = mInfo.mYAxis.dx_preclip + mInfo.mYAxis.dx_active + mInfo.mYAxis.dx_postclip + mInfo.mYAxis.dx_dualclip) {
  682.         sint32 v = mInfo.mYAxis.u + ((winsize-1) >> 16);
  683.         const sint32 dvdy = mInfo.mYAxis.dudx;
  684.  
  685.         do {
  686.             sint32 y = (v >> 16);
  687.  
  688.             if (y<0)
  689.                 y=0;
  690.             else if (y >= srch)
  691.                 y = srch-1;
  692.  
  693.             ProcessRow(dst, vdptroffset(src, y*srcpitch));
  694.  
  695.             vdptrstep(dst, dstpitch);
  696.             v += dvdy;
  697.         } while(--count);
  698.     }
  699.  
  700.     if (uint32 count = mInfo.mYAxis.dx_postcopy) {
  701.         const uint32 *srcrow = vdptroffset(src, srcpitch*(srch-1));
  702.         do {
  703.             ProcessRow(dst, srcrow);
  704.             vdptrstep(dst, dstpitch);
  705.         } while(--count);
  706.     }
  707. }
  708.  
  709. void VDResamplerSeparableStage::ProcessComplex() {
  710.     uint32 clipSpace = (mRowFiltW*3 + 3) & ~3;
  711.     uint32 paddedWidth = (mInfo.mXAxis.dx + 3) & ~3;
  712.     mTempSpace.resize(clipSpace + paddedWidth * mWinSize);
  713.  
  714.     uint32 *p = mTempSpace.data();
  715.     p += clipSpace;
  716.  
  717.     mpAllocWindow = &mWindow[2*mWinSize];
  718.  
  719.     for(uint32 i=0; i<mWinSize; ++i) {
  720.         mpAllocWindow[i] = p;
  721.         p += paddedWidth;
  722.     }
  723.  
  724.     const uint32 winsize = mWinSize;
  725.     const uint32 dx = mInfo.mXAxis.dx;
  726.  
  727.     const uint32 *src = (const uint32 *)mInfo.mpSrc;
  728.     const ptrdiff_t srcpitch = mInfo.mSrcPitch;
  729.     const sint32 srch = mInfo.mSrcH;
  730.     void *dst = mInfo.mpDst;
  731.     const ptrdiff_t dstpitch = mInfo.mDstPitch;
  732.     sint32 winpos = -1;
  733.     uint32 winidx = mWinSize>1 ? 1 : 0;
  734.     uint32 winallocnext = mWinSize>1 ? 1 : 0;
  735.  
  736.     std::fill(mWindow.begin(), mWindow.begin() + 2*mWinSize, mpAllocWindow[0]);
  737.  
  738.     if (mInfo.mYAxis.dx_precopy || mInfo.mYAxis.u < 0x10000) {
  739.         winpos = 0;
  740.  
  741.         ProcessRow(mWindow[0], src);
  742.     }
  743.  
  744.     if (uint32 count = mInfo.mYAxis.dx_precopy) {
  745.         do {
  746.             memcpy(dst, mWindow[0], dx * sizeof(uint32));
  747.             vdptrstep(dst, dstpitch);
  748.         } while(--count);
  749.     }
  750.  
  751.     if (uint32 count = mInfo.mYAxis.dx_preclip + mInfo.mYAxis.dx_active + mInfo.mYAxis.dx_postclip + mInfo.mYAxis.dx_dualclip) {
  752.         sint32 v = mInfo.mYAxis.u + ((winsize-1) >> 16);
  753.         const sint32 dvdy = mInfo.mYAxis.dudx;
  754.  
  755.         do {
  756.             sint32 desiredpos = (v >> 16) + winsize - 1;
  757.  
  758.             if (winpos < desiredpos - (sint32)winsize)
  759.                 winpos = desiredpos - (sint32)winsize;
  760.  
  761.             while(winpos+1 <= desiredpos) {
  762.                 ++winpos;
  763.                 if (winpos >= srch) {
  764.                     mWindow[winidx] = mWindow[winidx + winsize] = mWindow[winidx ? winidx-1 : winsize-1];
  765.                 } else {
  766.                     mWindow[winidx] = mWindow[winidx + winsize] = mpAllocWindow[winallocnext];
  767.                     if (++winallocnext >= winsize)
  768.                         winallocnext = 0;
  769.  
  770.                     ProcessRow(mWindow[winidx], vdptroffset(src, winpos*srcpitch));
  771.                 }
  772.                 if (++winidx >= winsize)
  773.                     winidx = 0;
  774.             }
  775.  
  776.             if (mpColStage)
  777.                 mpColStage->Process(dst, &mWindow[winidx], dx, v);
  778.             else
  779.                 memcpy(dst, mWindow[winidx], dx*sizeof(uint32));
  780.  
  781.             vdptrstep(dst, dstpitch);
  782.             v += dvdy;
  783.         } while(--count);
  784.     }
  785.  
  786.     if (uint32 count = mInfo.mYAxis.dx_postcopy) {
  787.         if (winpos < srch - 1) {
  788.             mWindow[winidx] = mWindow[winidx + winsize] = mpAllocWindow[winallocnext];
  789.             ProcessRow(mWindow[winidx], vdptroffset(src, srcpitch*(srch-1)));
  790.             if (++winidx >= winsize)
  791.                 winidx = 0;
  792.         }
  793.  
  794.         const void *p = mWindow[winidx + winsize - 1];
  795.         do {
  796.             memcpy(dst, p, dx * sizeof(uint32));
  797.             vdptrstep(dst, dstpitch);
  798.         } while(--count);
  799.     }
  800. }
  801.  
  802. void VDResamplerSeparableStage::ProcessRow(void *dst0, const void *src0) {
  803.     const uint32 *src = (const uint32 *)src0;
  804.     uint32 *dst = (uint32 *)dst0;
  805.  
  806.     // process pre-copy region
  807.     if (uint32 count = mInfo.mXAxis.dx_precopy) {
  808.         VDMemset32(dst, src[0], count);
  809.         dst += count;
  810.     }
  811.  
  812.     uint32 *p = mTempSpace.data();
  813.     sint32 u = mInfo.mXAxis.u;
  814.     const sint32 dudx = mInfo.mXAxis.dudx;
  815.  
  816.     // process dual-clip region
  817.     if (uint32 count = mInfo.mXAxis.dx_dualclip) {
  818.         VDMemset32(p, src[0], mRowFiltW);
  819.         memcpy(p + mRowFiltW, src+1, (mInfo.mSrcW-2)*sizeof(uint32));
  820.         VDMemset32(p + mRowFiltW + (mInfo.mSrcW-2), src[mInfo.mSrcW-1], mRowFiltW);
  821.  
  822.         mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx);
  823.         u += dudx*count;
  824.         dst += count;
  825.     } else {
  826.         // process pre-clip region
  827.         if (uint32 count = mInfo.mXAxis.dx_preclip) {
  828.             VDMemset32(p, src[0], mRowFiltW);
  829.             memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32));
  830.  
  831.             mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx);
  832.             u += dudx*count;
  833.             dst += count;
  834.         }
  835.  
  836.         // process active region
  837.         if (uint32 count = mInfo.mXAxis.dx_active) {
  838.             mpRowStage->Process(dst, src, count, u, dudx);
  839.             u += dudx*count;
  840.             dst += count;
  841.         }
  842.  
  843.         // process post-clip region
  844.         if (uint32 count = mInfo.mXAxis.dx_postclip) {
  845.             uint32 offset = mInfo.mSrcW + 1 - mRowFiltW;
  846.  
  847.             memcpy(p, src+offset, (mRowFiltW-1)*sizeof(uint32));
  848.             VDMemset32(p + (mRowFiltW-1), src[mInfo.mSrcW-1], mRowFiltW);
  849.  
  850.             mpRowStage->Process(dst, p, count, u - (offset<<16), dudx);
  851.             dst += count;
  852.         }
  853.     }
  854.  
  855.     // process post-copy region
  856.     if (uint32 count = mInfo.mXAxis.dx_postcopy) {
  857.         VDMemset32(dst, src[mInfo.mSrcW-1], count);
  858.     }
  859. }
  860.  
  861. ///////////////////////////////////////////////////////////////////////////
  862. //
  863. // resampler stages (scalar, x86)
  864. //
  865. ///////////////////////////////////////////////////////////////////////////
  866.  
  867. namespace {
  868.     struct ScaleInfo {
  869.         void *dst;
  870.         uintptr    src;
  871.         uint32    accum;
  872.         uint32    fracinc;
  873.         sint32    intinc;
  874.         uint32    count;
  875.     };
  876. }
  877.  
  878. #ifndef _M_AMD64
  879.     extern "C" void vdasm_resize_point32(const ScaleInfo *);
  880.  
  881.     class VDResamplerSeparablePointRowStageX86 : public IVDResamplerSeparableRowStage {
  882.     public:
  883.         int GetWindowSize() const {return 1;}
  884.         void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) {
  885.             ScaleInfo info;
  886.  
  887.             info.dst = (uint32 *)dst + w;
  888.             info.src = ((uintptr)src >> 2) + (u>>16);
  889.             info.accum = u<<16;
  890.             info.fracinc = dudx << 16;
  891.             info.intinc = (sint32)dudx >> 16;
  892.             info.count = -(sint32)w*4;
  893.  
  894.             vdasm_resize_point32(&info);
  895.         }
  896.     };
  897. #endif
  898.  
  899. ///////////////////////////////////////////////////////////////////////////
  900. //
  901. // resampler stages (MMX, x86)
  902. //
  903. ///////////////////////////////////////////////////////////////////////////
  904.  
  905. #ifndef _M_AMD64
  906.     extern "C" void vdasm_resize_point32_MMX(const ScaleInfo *);
  907.  
  908.     class VDResamplerSeparablePointRowStageMMX : public IVDResamplerSeparableRowStage {
  909.     public:
  910.         int GetWindowSize() const {return 1;}
  911.         void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) {
  912.             ScaleInfo info;
  913.  
  914.             info.dst = (uint32 *)dst + w;
  915.             info.src = ((uintptr)src >> 2) + (u>>16);
  916.             info.accum = u<<16;
  917.             info.fracinc = dudx << 16;
  918.             info.intinc = (sint32)dudx >> 16;
  919.             info.count = -(sint32)w*4;
  920.  
  921.             vdasm_resize_point32_MMX(&info);
  922.         }
  923.     };
  924.  
  925.     extern "C" void vdasm_resize_interp_row_run_MMX(void *dst, const void *src, uint32 width, sint64 xaccum, sint64 x_inc);
  926.     extern "C" void vdasm_resize_interp_col_run_MMX(void *dst, const void *src1, const void *src2, uint32 width, uint32 yaccum);
  927.     extern "C" void vdasm_resize_ccint_row_MMX(void *dst, const void *src, uint32 count, uint32 xaccum, sint32 xinc, const void *tbl);
  928.     extern "C" void vdasm_resize_ccint_col_MMX(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl);
  929.     extern "C" long vdasm_resize_table_col_MMX(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac);
  930.     extern "C" long vdasm_resize_table_row_MMX(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac);
  931.  
  932.     class VDResamplerSeparableLinearRowStageMMX : public IVDResamplerSeparableRowStage {
  933.     public:
  934.         int GetWindowSize() const {return 2;}
  935.         void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) {
  936.             vdasm_resize_interp_row_run_MMX(dst0, src0, w, (sint64)u << 16, (sint64)dudx << 16);
  937.         }
  938.     };
  939.  
  940.     class VDResamplerSeparableLinearColStageMMX : public IVDResamplerSeparableColStage {
  941.     public:
  942.         int GetWindowSize() const {return 2;}
  943.         void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) {
  944.             vdasm_resize_interp_col_run_MMX(dst0, srcarray[0], srcarray[1], w, phase);
  945.         }
  946.     };
  947.  
  948.     class VDResamplerSeparableCubicRowStageMMX : public IVDResamplerSeparableRowStage {
  949.     public:
  950.         VDResamplerSeparableCubicRowStageMMX(double A)
  951.             : mFilterBank(1024)
  952.         {
  953.             sint32 *p = mFilterBank.data();
  954.             GenerateTable(p, VDResamplerCubicFilter(1.0, A));
  955.             SwizzleTable(p, 512);
  956.         }
  957.  
  958.         int GetWindowSize() const {return 4;}
  959.         void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) {
  960.             vdasm_resize_ccint_row_MMX(dst0, src0, w, u, dudx, mFilterBank.data());
  961.         }
  962.  
  963.     protected:
  964.         vdblock<sint32, vdaligned_alloc<sint32> > mFilterBank;
  965.     };
  966.  
  967.     class VDResamplerSeparableCubicColStageMMX : public IVDResamplerSeparableColStage {
  968.     public:
  969.         VDResamplerSeparableCubicColStageMMX(double A)
  970.             : mFilterBank(1024)
  971.         {
  972.             sint32 *p = mFilterBank.data();
  973.             GenerateTable(p, VDResamplerCubicFilter(1.0, A));
  974.             SwizzleTable(p, 512);
  975.         }
  976.  
  977.         int GetWindowSize() const {return 4;}
  978.         void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) {
  979.             vdasm_resize_ccint_col_MMX(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc));
  980.         }
  981.  
  982.     protected:
  983.         vdblock<sint32, vdaligned_alloc<sint32> > mFilterBank;
  984.     };
  985.  
  986.     class VDResamplerSeparableTableRowStageMMX : public VDResamplerSeparableTableRowStage {
  987.     public:
  988.         VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter)
  989.             : VDResamplerSeparableTableRowStage(filter)
  990.         {
  991.             SwizzleTable(mFilterBank.data(), mFilterBank.size() >> 1);
  992.         }
  993.  
  994.         void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) {
  995.             vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), mFilterBank.size() >> 8, w, u, dudx);
  996.         }
  997.     };
  998.  
  999.     class VDResamplerSeparableTableColStageMMX : public VDResamplerSeparableTableColStage {
  1000.     public:
  1001.         VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter)
  1002.             : VDResamplerSeparableTableColStage(filter)
  1003.         {
  1004.             SwizzleTable(mFilterBank.data(), mFilterBank.size() >> 1);
  1005.         }
  1006.  
  1007.         void Process(void *dst, const void *const *src, uint32 w, sint32 phase) {
  1008.             vdasm_resize_table_col_MMX((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), mFilterBank.size() >> 8, w, (phase >> 8) & 0xff);
  1009.         }
  1010.     };
  1011. #endif
  1012.  
  1013. ///////////////////////////////////////////////////////////////////////////
  1014. //
  1015. // resampler stages (SSE2, x86)
  1016. //
  1017. ///////////////////////////////////////////////////////////////////////////
  1018.  
  1019. #ifndef _M_AMD64
  1020.     extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac);
  1021.     extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac);
  1022.     extern "C" void vdasm_resize_ccint_col_SSE2(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl);
  1023.  
  1024.     class VDResamplerSeparableCubicColStageSSE2 : public VDResamplerSeparableCubicColStageMMX {
  1025.     public:
  1026.         VDResamplerSeparableCubicColStageSSE2(double A)
  1027.             : VDResamplerSeparableCubicColStageMMX(A)
  1028.         {
  1029.         }
  1030.  
  1031.         void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) {
  1032.             vdasm_resize_ccint_col_SSE2(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc));
  1033.         }
  1034.     };
  1035.  
  1036.     class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerSeparableTableRowStageMMX {
  1037.     public:
  1038.         VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter)
  1039.             : VDResamplerSeparableTableRowStageMMX(filter)
  1040.         {
  1041.         }
  1042.  
  1043.         void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) {
  1044.             vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), mFilterBank.size() >> 8, w, u, dudx);
  1045.         }
  1046.     };
  1047.  
  1048.     class VDResamplerSeparableTableColStageSSE2 : public VDResamplerSeparableTableColStageMMX {
  1049.     public:
  1050.         VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter)
  1051.             : VDResamplerSeparableTableColStageMMX(filter)
  1052.         {
  1053.         }
  1054.  
  1055.         void Process(void *dst, const void *const *src, uint32 w, sint32 phase) {
  1056.             vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), mFilterBank.size() >> 8, w, (phase >> 8) & 0xff);
  1057.         }
  1058.     };
  1059. #endif
  1060.  
  1061. ///////////////////////////////////////////////////////////////////////////
  1062. //
  1063. // resampler stages (SSE2, AMD64)
  1064. //
  1065. ///////////////////////////////////////////////////////////////////////////
  1066.  
  1067. #ifdef _M_AMD64
  1068.     extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w);
  1069.     extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac);
  1070.  
  1071.     class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerSeparableTableRowStage {
  1072.     public:
  1073.         VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter)
  1074.             : VDResamplerSeparableTableRowStage(filter)
  1075.         {
  1076.             SwizzleTable(mFilterBank.data(), mFilterBank.size() >> 1);
  1077.         }
  1078.  
  1079.         void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) {
  1080.             vdasm_resize_table_row_SSE2((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), mFilterBank.size() >> 8, w, u, dudx);
  1081.         }
  1082.     };
  1083.  
  1084.     class VDResamplerSeparableTableColStageSSE2 : public VDResamplerSeparableTableColStage {
  1085.     public:
  1086.         VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter)
  1087.             : VDResamplerSeparableTableColStage(filter)
  1088.         {
  1089.             SwizzleTable(mFilterBank.data(), mFilterBank.size() >> 1);
  1090.         }
  1091.  
  1092.         void Process(void *dst, const void *const *src, uint32 w, sint32 phase) {
  1093.             const unsigned filtSize = mFilterBank.size() >> 8;
  1094.  
  1095.             vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data() + filtSize*((phase >> 8) & 0xff), filtSize, w);
  1096.         }
  1097.     };
  1098. #endif
  1099.  
  1100.  
  1101. ///////////////////////////////////////////////////////////////////////////
  1102. //
  1103. // the resampler (finally)
  1104. //
  1105. ///////////////////////////////////////////////////////////////////////////
  1106.  
  1107. class VDPixmapResampler : public IVDPixmapResampler {
  1108. public:
  1109.     VDPixmapResampler();
  1110.     ~VDPixmapResampler();
  1111.  
  1112.     void SetSplineFactor(double A) { mSplineFactor = A; }
  1113.     bool Init(double dw, double dh, int dstformat, double sw, double sh, int srcformat, FilterMode hfilter, FilterMode vfilter, bool bInterpolationOnly);
  1114.     void Shutdown();
  1115.  
  1116.     void Process(const VDPixmap& dst, double dx1, double dy1, double dx2, double dy2, const VDPixmap& src, double sx, double sy);
  1117.  
  1118. protected:
  1119.     IVDResamplerSeparableRowStage *CreateRowStage(IVDResamplerFilter&);
  1120.     IVDResamplerSeparableColStage *CreateColStage(IVDResamplerFilter&);
  1121.  
  1122.     IVDResamplerStage    *mpRoot;
  1123.     double                mSplineFactor;
  1124.     VDResamplerInfo        mInfo;
  1125.     VDSteppedAllocator    mStageAllocator;
  1126. };
  1127.  
  1128. IVDPixmapResampler *VDCreatePixmapResampler() { return new VDPixmapResampler; }
  1129.  
  1130. VDPixmapResampler::VDPixmapResampler()
  1131.     : mpRoot(NULL)
  1132.     , mSplineFactor(-0.6)
  1133. {
  1134. }
  1135.  
  1136. VDPixmapResampler::~VDPixmapResampler() {
  1137.     Shutdown();
  1138. }
  1139.  
  1140. bool VDPixmapResampler::Init(double dw, double dh, int dstformat, double sw, double sh, int srcformat, FilterMode hfilter, FilterMode vfilter, bool bInterpolationOnly) {
  1141.     Shutdown();
  1142.  
  1143.     if (dstformat != srcformat || srcformat != nsVDPixmap::kPixFormat_XRGB8888)
  1144.         return false;
  1145.  
  1146.     // kill flips
  1147.     dw = fabs(dw);
  1148.     dh = fabs(dh);
  1149.     sw = fabs(sw);
  1150.     sh = fabs(sh);
  1151.  
  1152.     // compute gradients, using truncation toward zero
  1153.     unsigned fpucwsave = _controlfp(0, 0);
  1154.     _controlfp(_RC_CHOP, _MCW_RC);
  1155.  
  1156.     sint32 dudx = (sint32)((sw * 65536.0) / dw);
  1157.     sint32 dvdy = (sint32)((sh * 65536.0) / dh);
  1158.  
  1159.     _controlfp(fpucwsave, _MCW_RC);
  1160.  
  1161.     mInfo.mXAxis.Init(dudx);
  1162.     mInfo.mYAxis.Init(dvdy);
  1163.  
  1164.     // construct stages
  1165.     double x_2fc = 1.0;
  1166.     double y_2fc = 1.0;
  1167.  
  1168.     if (!bInterpolationOnly && dw < sw)
  1169.         x_2fc = dw/sw;
  1170.     if (!bInterpolationOnly && dh < sh)
  1171.         y_2fc = dh/sh;
  1172.  
  1173.     IVDResamplerSeparableRowStage *pRowStage = NULL;
  1174.     IVDResamplerSeparableColStage *pColStage = NULL;
  1175.  
  1176.     if (hfilter == kFilterPoint) {
  1177. #ifndef _M_AMD64
  1178.         long flags = CPUGetEnabledExtensions();
  1179.  
  1180.         if (flags & CPUF_SUPPORTS_MMX)
  1181.             pRowStage = new(mStageAllocator) VDResamplerSeparablePointRowStageMMX;
  1182.         else
  1183.             pRowStage = new(mStageAllocator) VDResamplerSeparablePointRowStageX86;
  1184. #else        
  1185.         pRowStage = new(mStageAllocator) VDResamplerSeparablePointRowStage;
  1186. #endif
  1187.     } else if (hfilter == kFilterLinear) {
  1188.         if (x_2fc >= 1.0) {
  1189. #ifndef _M_AMD64
  1190.             long flags = CPUGetEnabledExtensions();
  1191.  
  1192.             if (flags & CPUF_SUPPORTS_MMX)
  1193.                 pRowStage = new(mStageAllocator) VDResamplerSeparableLinearRowStageMMX;
  1194.             else
  1195. #endif
  1196.                 pRowStage = new(mStageAllocator) VDResamplerSeparableLinearRowStage;
  1197.         } else
  1198.             pRowStage = CreateRowStage(VDResamplerLinearFilter(x_2fc));
  1199.     } else if (hfilter == kFilterCubic) {
  1200. #ifndef _M_AMD64
  1201.         long flags = CPUGetEnabledExtensions();
  1202.  
  1203.         if (x_2fc >= 1.0 && (flags & CPUF_SUPPORTS_MMX))
  1204.             pRowStage = new(mStageAllocator) VDResamplerSeparableCubicRowStageMMX(mSplineFactor);
  1205.         else
  1206. #endif
  1207.             pRowStage = CreateRowStage(VDResamplerCubicFilter(x_2fc, mSplineFactor));
  1208.     } else if (hfilter == kFilterLanczos3)
  1209.         pRowStage = CreateRowStage(VDResamplerLanczos3Filter(x_2fc));
  1210.  
  1211.     if (hfilter == kFilterLinear) {
  1212.         if (y_2fc >= 1.0) {
  1213. #ifndef _M_AMD64
  1214.             long flags = CPUGetEnabledExtensions();
  1215.  
  1216.             if (flags & CPUF_SUPPORTS_MMX)
  1217.                 pColStage = new(mStageAllocator) VDResamplerSeparableLinearColStageMMX;
  1218.             else
  1219. #endif
  1220.                 pColStage = new(mStageAllocator) VDResamplerSeparableLinearColStage;
  1221.         } else
  1222.             pColStage = CreateColStage(VDResamplerLinearFilter(y_2fc));
  1223.     } else if (hfilter == kFilterCubic) {
  1224. #ifndef _M_AMD64
  1225.         long flags = CPUGetEnabledExtensions();
  1226.  
  1227.         if (y_2fc >= 1.0 && (flags & CPUF_SUPPORTS_MMX)) {
  1228.             if (flags & CPUF_SUPPORTS_SSE2)
  1229.                 pColStage = new(mStageAllocator) VDResamplerSeparableCubicColStageSSE2(mSplineFactor);
  1230.             else
  1231.                 pColStage = new(mStageAllocator) VDResamplerSeparableCubicColStageMMX(mSplineFactor);
  1232.         } else
  1233. #endif
  1234.             pColStage = CreateColStage(VDResamplerCubicFilter(y_2fc, mSplineFactor));
  1235.     } else if (hfilter == kFilterLanczos3)
  1236.         pColStage = CreateColStage(VDResamplerLanczos3Filter(y_2fc));
  1237.  
  1238.     mpRoot = new(mStageAllocator) VDResamplerSeparableStage(
  1239.                     pRowStage,
  1240.                     pColStage
  1241.                     );
  1242.  
  1243.     return true;
  1244. }
  1245.  
  1246. IVDResamplerSeparableRowStage *VDPixmapResampler::CreateRowStage(IVDResamplerFilter& filter) {
  1247. #ifndef _M_AMD64
  1248.     long flags = CPUGetEnabledExtensions();
  1249.  
  1250.     if (flags & CPUF_SUPPORTS_SSE2)
  1251.         return new(mStageAllocator) VDResamplerSeparableTableRowStageSSE2(filter);
  1252.     else if (flags & CPUF_SUPPORTS_MMX)
  1253.         return new(mStageAllocator) VDResamplerSeparableTableRowStageMMX(filter);
  1254.     else
  1255.         return new(mStageAllocator) VDResamplerSeparableTableRowStage(filter);
  1256. #else
  1257.     return new(mStageAllocator) VDResamplerSeparableTableRowStageSSE2(filter);
  1258. #endif
  1259. }
  1260.  
  1261. IVDResamplerSeparableColStage *VDPixmapResampler::CreateColStage(IVDResamplerFilter& filter) {
  1262. #ifndef _M_AMD64
  1263.     long flags = CPUGetEnabledExtensions();
  1264.  
  1265.     if (flags & CPUF_SUPPORTS_SSE2)
  1266.         return new(mStageAllocator) VDResamplerSeparableTableColStageSSE2(filter);
  1267.     else if (flags & CPUF_SUPPORTS_MMX)
  1268.         return new(mStageAllocator) VDResamplerSeparableTableColStageMMX(filter);
  1269.     else
  1270.         return new(mStageAllocator) VDResamplerSeparableTableColStage(filter);
  1271. #else
  1272.     return new(mStageAllocator) VDResamplerSeparableTableColStageSSE2(filter);
  1273. #endif
  1274. }
  1275.  
  1276. void VDPixmapResampler::Shutdown() {
  1277.     if (mpRoot) {
  1278.         mpRoot->~IVDResamplerStage();
  1279.         mpRoot = NULL;
  1280.     }
  1281.  
  1282.     mStageAllocator.clear();
  1283. }
  1284.  
  1285. void VDPixmapResampler::Process(const VDPixmap& dst, double dx1, double dy1, double dx2, double dy2, const VDPixmap& src, double sx1, double sy1) {
  1286.     if (!mpRoot)
  1287.         return;
  1288.  
  1289.     // convert coordinates to fixed point
  1290.     sint32 fdx1 = (sint32)(dx1 * 65536.0);
  1291.     sint32 fdy1 = (sint32)(dy1 * 65536.0);
  1292.     sint32 fdx2 = (sint32)(dx2 * 65536.0);
  1293.     sint32 fdy2 = (sint32)(dy2 * 65536.0);
  1294.     sint32 fsx1 = (sint32)(sx1 * 65536.0);
  1295.     sint32 fsy1 = (sint32)(sy1 * 65536.0);
  1296.  
  1297.     // determine integer destination rectangle (OpenGL coordinates)
  1298.     sint32 idx1 = (fdx1 + 0x7fff) >> 16;
  1299.     sint32 idy1 = (fdy1 + 0x7fff) >> 16;
  1300.     sint32 idx2 = (fdx2 + 0x7fff) >> 16;
  1301.     sint32 idy2 = (fdy2 + 0x7fff) >> 16;
  1302.  
  1303.     // convert destination flips to source flips
  1304.     if (idx1 > idx2) {
  1305.         std::swap(idx1, idx2);
  1306.         sx1 += scale32x32_fp16(mInfo.mXAxis.dudx, idx2 - idx1);
  1307.     }
  1308.  
  1309.     if (idy1 > idy2) {
  1310.         std::swap(idy1, idy2);
  1311.         sy1 += scale32x32_fp16(mInfo.mYAxis.dudx, idy2 - idy1);
  1312.     }
  1313.  
  1314.     // clip destination rect
  1315.     if (idx1 < 0)
  1316.         idx1 = 0;
  1317.     if (idy1 < 0)
  1318.         idy1 = 0;
  1319.     if (idx2 > dst.w)
  1320.         idx2 = dst.w;
  1321.     if (idy2 > dst.h)
  1322.         idy2 = dst.h;
  1323.  
  1324.     // check for degenerate conditions
  1325.     if (idx1 >= idx2 || idy1 >= idy2)
  1326.         return;
  1327.  
  1328.     // render
  1329.     const sint32 winw = mpRoot->GetHorizWindowSize();
  1330.     const sint32 winh = mpRoot->GetVertWindowSize();
  1331.  
  1332.     fsx1 -= (winw-1)<<15;
  1333.     fsy1 -= (winh-1)<<15;
  1334.  
  1335.     mInfo.mXAxis.Compute(idx1, idx2, fdx1, fsx1, src.w, winw);
  1336.     mInfo.mYAxis.Compute(idy1, idy2, fdy1, fsy1, src.h, winh);
  1337.  
  1338.     mInfo.mpSrc = src.data;
  1339.     mInfo.mSrcPitch = src.pitch;
  1340.     mInfo.mSrcW = src.w;
  1341.     mInfo.mSrcH = src.h;
  1342.     mInfo.mpDst = vdptroffset(dst.data, dst.pitch * idy1 + idx1*4);
  1343.     mInfo.mDstPitch = dst.pitch;
  1344.  
  1345.     if (mpRoot) {
  1346.         mpRoot->Process(mInfo);
  1347.  
  1348.         VDCPUCleanupExtensions();
  1349.     }
  1350. }
  1351.  
  1352. bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter) {
  1353.     VDPixmapResampler r;
  1354.  
  1355.     if (!r.Init(dst.w, dst.h, dst.format, src.w, src.h, src.format, filter, filter, false))
  1356.         return false;
  1357.  
  1358.     r.Process(dst, 0, 0, dst.w, dst.h, src, 0, 0);
  1359.     return true;
  1360. }
  1361.